package oojo.data.impl.exec;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.NonUniqueResultException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import oojo.data.Query;
import oojo.data.QueryException;
import oojo.data.impl.BaseQuery;
import oojo.data.impl.Properties;
import oojo.data.spec.FindById;

public class FindByIdQuery<E> extends BaseQuery<E, E> {

    private static final Logger logger = LoggerFactory.getLogger(FindByIdQuery.class);
    
    public Class<?> getQueryClass() {
        return FindById.class;
    }

    @SuppressWarnings("unchecked")
    public E execute(Query<E, E> findById) {
        logger.debug("---> execute(spec)");
        
        try {
            FindById<E> spec = (FindById<E>) findById; 
            EntityManager entityManager = getRepository().getEntityManager();

            if (spec.getJoins() == null) {
                return (E) entityManager.find(getRepository().getEntityClass(), spec.getId());
            }

            StringBuilder sb = new StringBuilder();
            sb.append("select e from ").append(getRepository().getEntityClass().getName()).append(" e");

            for (String rel : spec.getJoins()) {
                sb.append(" left join fetch e.").append(rel);
            }

            String idProperty = Properties.idProperty(getRepository().getEntityClass());
            sb.append(" where e." + idProperty + " = :id");

            javax.persistence.Query query = entityManager.createQuery(sb.toString());
            query.setParameter("id", spec.getId());
            List<E> results = (List<E>) query.getResultList();
            
            switch (results.size()) {
            case 0:
                return null;
            case 1:
                return results.get(0);
            default:
                throw new NonUniqueResultException("Found " + results.size() + " results");
            }
        } catch (Exception ex) {
            throw new QueryException(ex);
        }
    }
}
